home *** CD-ROM | disk | FTP | other *** search
- /*
- * C code from the article
- * "Fast Collision Detection of Moving Convex Polyhedra"
- * by Rich Rabbitz, rrabbitz%pgn138fs@serling.motown.ge.com
- * in "Graphics Gems IV", Academic Press, 1994
- */
-
- #include <math.h>
-
- typedef long Boolean;
-
- #define FUZZ (0.00001)
- #define TRUE (1)
- #define FALSE (0)
- #define MAX_VERTS (1026)
-
- #define ABS(x) ( (x) > 0 ? (x) : -(x) )
- #define EQZ(x) ( ABS((x)) < FUZZ ? TRUE : FALSE )
-
- #define DOT3(u,v) ( u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
- #define VECADD3(r,u,v) { r[0]=u[0]+v[0]; r[1]=u[1]+v[1]; r[2]=u[2]+v[2]; }
- #define VECADDS3(r,a,u,v){r[0]=a*u[0]+v[0]; r[1]=a*u[1]+v[1]; r[2]=a*u[2]+v[2];}
- #define VECSMULT3(a,u) { u[0]= a * u[0]; u[1]= a * u[1]; u[2]= a * u[2]; }
- #define VECSUB3(r,u,v) { r[0]=u[0]-v[0]; r[1]=u[1]-v[1]; r[2]=u[2]-v[2]; }
- #define CPVECTOR3(u,v) { u[0]=v[0]; u[1]=v[1]; u[2]=v[2]; }
- #define VECNEGATE3(u) { u[0]=(-u[0]); u[1]=(-u[1]); u[2]=(-u[2]); }
-
- #define GET(u,i,j,s) (*(u+i*s+j))
- #define GET3(u,i,j,k,s) (*(u+i*(s*2)+(j*2)+k))
-
- /**************************************************************************
- *
- * The structure polyhedron is used to store the geometry of the primitives
- * used in this collision detection example. Since the collision detection
- * algorithm only needs to operate on the vertex set of a polyhedron, and
- * no rendering is done in this example, the faces and edges of a
- * polyhedron are not stored. Adding faces and edges to the structure for
- * rendering purposes should be straight forward and will have no effect on
- * the collision detection computations.
- *
- **************************************************************************/
-
- typedef struct polyhedron {
- double verts[MAX_VERTS][3]; /* 3-D vertices of polyhedron. */
- int m; /* number of 3-D vertices. */
- double trn[3]; /* translational position in world coords. */
- double itrn[3]; /* inverse of translational position. */
- } *Polyhedron;
-
- /**************************************************************************
- *
- * The structure couple is used to store the information required to
- * repeatedly test a pair of polyhedra for collision. This information
- * includes : a reference to each polyhedron, a flag indicating if there
- * is a cached prospective proper separating plane, two points for
- * constructing the proper separating plane, and possibly a cached set
- * of points from each polyhedron for speeding up the distance algorithm.
- *
- **************************************************************************/
-
- typedef struct couple {
- Polyhedron polyhdrn1; /* First polyhedron of collision test. */
- Polyhedron polyhdrn2; /* Second polyhedron of collision test. */
- Boolean plane_exists; /* prospective separating plane flag */
- double pln_pnt1[3]; /* 1st point used to form separating plane. */
- double pln_pnt2[3]; /* 2nd point used to form separating plane. */
- int vert_indx[4][2]; /* cached points for distance algorithm. */
- int n; /* number of cached points, if any. */
- } *Couple;
-
-
- /*** Arrays for vertex sets of three primitives ***/
-
- double box[24];
- double cyl[108];
- double sphere[1026];
-
- /*** RJR 08/20/93 ***********************************************************
- *
- * Function to create vertex set of a polyhedron used to represent a
- * box primitive.
- *
- * On Entry:
- * box_verts - an empty array of type double of size 24 or more.
- *
- * On Exit:
- * box_verts - vertices of a polyhedron representing a box with
- * dimensions length = 5.0, width = 5.0, and height = 5.0.
- *
- * Function Return : none.
- *
- ****************************************************************************/
-
- void mak_box(box_verts)
- double box_verts[];
- {
- int i;
- static double verts[24] =
- {-5.0, 5.0, 5.0, -5.0, 5.0, -5.0, 5.0, 5.0, -5.0,
- 5.0, 5.0, 5.0, -5.0, -5.0, 5.0, -5.0, -5.0, -5.0,
- 5.0, -5.0, -5.0, 5.0, -5.0, 5.0};
-
- for (i = 0; i < 24; i++)
- box_verts[i] = verts[i];
- }
-
-
- /*** RJR 08/20/93 ***********************************************************
- *
- * Function to create vertex set of a polyhedron used to approximate
- * a cylinder primitive.
- *
- * On Entry:
- * cyl_verts - an empty array of type double of size 108 or more.
- *
- * On Exit:
- * cyl_verts - vertices of a polyhedron approximating a cylinder with
- * a base radius = 5.0, and height = 5.0.
- * Function Return : none.
- *
- ****************************************************************************/
-
- void mak_cyl(cyl_verts)
- double cyl_verts[];
- {
- int i;
- double *pD_1, *pD_2, rads, stp, radius;
-
- pD_1 = cyl_verts; pD_2 = cyl_verts + 54;
- stp = 0.34906585; rads = 0.0; radius = 5.0;
-
- for (i = 0; i < 18; i++) {
- pD_1[0] = pD_2[0] = radius * cos(rads); /* X for top and bot. */
- pD_1[1] = 5.0; /* Y for top */
- pD_2[1] = 0.0; /* Y for bot. */
- pD_1[2] = pD_2[2] = -(radius * sin(rads)); /* Z for top and bot. */
- rads += stp; pD_1 += 3; pD_2 += 3;
- }
- }
-
-
- /*** RJR 08/20/93 ***********************************************************
- *
- * Function to create vertex set of a polyhedron used to approximate
- * a sphere primitive.
- *
- * On Entry:
- * sph_verts - an empty array of type double of size 1026 or more.
- *
- * On Exit:
- * sph_verts - vertices of a polyhedron approximating a sphere with
- * a radius = 5.25.
- * Function Return : none.
- *
- ****************************************************************************/
-
- void mak_sph(sph_verts)
- double sph_verts[];
- {
- int i, j;
- double rads_1, rads_2, stp_1, stp_2, *pD_1, *pD_2, radius;
-
- rads_1 = 1.570796327; stp_1 = 0.174532935;
- rads_2 = 0.0; stp_2 = 0.34906585;
- pD_1 = sph_verts; radius = 5.25;
-
- for (i = 0; i < 19; i++) {
- pD_1[0] = radius * cos(rads_1); pD_1[1] = radius * sin(rads_1);
- pD_1[2] = 0.0;
- if (EQZ(pD_1[0]))
- pD_1[0] = 0.01;
- rads_2 = 0.0; stp_2 = 0.34906585;
-
- for (j = 0; j < 18; j++) {
- pD_2 = pD_1 + j * 3;
- pD_2[0] = pD_1[0] * cos(rads_2) - pD_1[2] * sin(rads_2); /* X */
- pD_2[1] = pD_1[1]; /* Y */
- pD_2[2] = -(pD_1[0] * sin(rads_2) + pD_1[2] * cos(rads_2)); /* Z */
- rads_2 += stp_2;
- }
- pD_1 += 54; rads_1 -= stp_1;
- }
- }
-
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to evaluate the support and contact functions at A for a given
- * polytope. See equations (6) & (7).
- *
- * On Entry:
- * P - table of 3-element points containing polytope vertices.
- * r - number of points in table.
- * A - vector at which support and contact functions will be evaluated.
- * Cp - empty 3-element array.
- * P_i - pointer to an int.
- *
- * On Exit:
- * Cp - contact point of P w.r.t. A.
- * P_i - index into P of contact point.
- *
- * Function Return :
- * the result of the evaluation of eq. (6) for P and A.
- *
- ****************************************************************************/
-
- double Hp(P, r, A, Cp, P_i)
- double P[][3], A[], Cp[];
- int r, *P_i;
- {
- int i;
- double max_val, val;
-
- max_val = DOT3(P[0], A); *P_i = 0;
-
- for (i = 1; i < r; i++) {
- val = DOT3(P[i], A);
- if (val > max_val) {
- *P_i = i;
- max_val = val;
- }
- }
- CPVECTOR3(Cp, P[*P_i]);
-
- return max_val;
- }
-
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to evaluate the support and contact functions at A for the
- * set difference of two polytopes. See equations (8) & (9).
- *
- * On Entry:
- * P1 - table of 3-element points containing first polytope's vertices.
- * m1 - number of points in P1.
- * P2 - table of 3-element points containing second polytope's vertices.
- * m2 - number of points in P2.
- * A - vector at which to evaluate support and contact functions.
- * Cs - an empty array of size 3.
- * P1_i - a pointer to an int.
- * P2_i - a pointer to an int.
- *
- * On Exit:
- * Cs - solution to equation 9.
- * P1_i - index into P1 for solution to equation 9.
- * P2_i - index into P2 for solution to equation 9.
- *
- * Function Return :
- * the result of the evaluation of eq. (8) for P1 and P2 at A.
- *
- ****************************************************************************/
-
- double Hs(P1, m1, P2, m2, A, Cs, P1_i, P2_i)
- double P1[][3], P2[][3], A[], Cs[];
- int m1, m2, *P1_i, *P2_i;
- {
- double Cp_1[3], Cp_2[3], neg_A[3], Hp_1, Hp_2;
-
- Hp_1 = Hp(P1, m1, A, Cp_1, P1_i);
-
- CPVECTOR3(neg_A, A);
- VECNEGATE3(neg_A);
- Hp_2 = Hp(P2, m2, neg_A, Cp_2, P2_i);
-
- VECSUB3(Cs ,Cp_1, Cp_2);
-
- return (Hp_1 + Hp_2);
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Alternate function to compute the point in a polytope closest to the
- * origin in 3-space. The polytope size m is restricted to 1 < m <= 4.
- * This function is called only when comp_sub_dist fails.
- *
- * On Entry:
- * stop_index - number of sets to test.
- * D_P - array of determinants for each set.
- * Di_P - cofactors for each set.
- * Is - indices for each set.
- * c2 - row size offset.
- *
- * On Exit:
- *
- * Function Return :
- * the index of the set that is numerically closest to eq. (14).
- *
- ****************************************************************************/
-
- int sub_dist_back(P, stop_index, D_P, Di_P, Is, c2)
- double P[][3], Di_P[][4], *D_P;
- int stop_index, *Is, c2;
- {
- Boolean first, pass;
- int i, k, s, is, best_s;
- float sum, v_aff, best_v_aff;
-
- first = TRUE; best_s = -1;
- for (s = 0; s < stop_index; s++) {
- pass = TRUE;
- if (D_P[s] > 0.0) {
- for (i = 1; i <= GET(Is,s,0,c2); i++) {
- is = GET(Is,s,i,c2);
- if (Di_P[s][is] <= 0.0)
- pass = FALSE;
- }
- }
- else
- pass = FALSE;
-
- if (pass) {
-
- /*** Compute equation (33) in Gilbert ***/
-
- k = GET(Is,s,1,c2);
- sum = 0;
- for (i = 1; i <= GET(Is, s, 0, c2); i++) {
- is = GET(Is,s,i,c2);
- sum += Di_P[s][is] * DOT3(P[is],P[k]);
- }
- v_aff = sqrt(sum / D_P[s]);
- if (first) {
- best_s = s;
- best_v_aff = v_aff;
- first = FALSE;
- }
- else {
- if (v_aff < best_v_aff) {
- best_s = s;
- best_v_aff = v_aff;
- }
- }
- }
- }
- if (best_s == -1) {
- printf("backup failed\n");
- exit(0);
- }
- return best_s;
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to compute the point in a polytope closest to the origin in
- * 3-space. The polytope size m is restricted to 1 < m <= 4.
- *
- * On Entry:
- * P - table of 3-element points containing polytope's vertices.
- * m - number of points in P.
- * jo - table of indices for storing Dj_P cofactors in Di_P.
- * Is - indices into P for all sets of subsets of P.
- * IsC - indices into P for complement sets of Is.
- * near_pnt - an empty array of size 3.
- * near_indx - an empty array of size 4.
- * lambda - an empty array of size 4.
- *
- * On Exit:
- * near_pnt - the point in P closest to the origin.
- * near_indx - indices for a subset of P which is affinely independent.
- * See eq. (14).
- * lambda - the lambda as in eq. (14).
- *
- * Function Return :
- * the number of entries in near_indx and lambda.
- *
- ****************************************************************************/
-
- int comp_sub_dist(P, m, jo, Is, IsC, near_pnt, near_indx, lambda)
- double P[][3], near_pnt[], lambda[];
- int m, *jo, *Is, *IsC, near_indx[];
- {
- Boolean pass, fail;
- int i, j, k, isp, is, s, row, col, stop_index, c1, c2;
- double D_P[15], x[3], Dj_P, Di_P[15][4];
- static int combinations[5] = {0,0,3,7,15};
-
- stop_index = combinations[m]; /** how many subsets in P **/
- c1 = m; c2 = m + 1; /** row offsets for IsC and Is **/
-
- /** Initialize Di_P for singletons **/
-
- Di_P[0][0] = Di_P[1][1] = Di_P[2][2] = Di_P[3][3] = 1.0;
- s = 0; pass = FALSE;
-
- while ((s < stop_index) && (!pass)) { /* loop through each subset */
- D_P[s] = 0.0; fail = FALSE;
- for (i = 1; i <= GET(Is,s,0,c2); i++) { /** loop through all Is **/
- is = GET(Is,s,i,c2);
- if (Di_P[s][is] > 0.0) /** Condition 2 Theorem 2 **/
- D_P[s] += Di_P[s][is]; /** sum from eq. (16) **/
- else
- fail = TRUE;
- }
-
- for (j = 1; j <= GET(IsC,s,0,c1); j++) { /** loop through all IsC **/
- Dj_P = 0; k = GET(Is,s,1,c2);
- isp = GET(IsC,s,j,c1);
-
- for (i = 1; i <= GET(Is,s,0,c2); i++) {
- is = GET(Is,s,i,c2);
- VECSUB3(x, P[k], P[isp]); /** Wk - Wj eq. (18) **/
- Dj_P += Di_P[s][is] * DOT3(P[is], x); /** sum from eq. (18) **/
- }
- row = GET3(jo,s,isp,0,c1);
- col = GET3(jo,s,isp,1,c1);
- Di_P[row][col] = Dj_P; /** add new cofactors **/
-
- if (Dj_P > 0.00001) /** Condition 3 Theorem 2 **/
- fail = TRUE;
- }
- if ((!fail) && (D_P[s] > 0.0)) /** Conditions 2 && 3 && 1 Theorem 2 **/
- pass = TRUE;
- else
- s++;
- }
- if (!pass) {
- printf("*** using backup procedure in sub_dist\n");
- s = sub_dist_back(P, stop_index, D_P, Di_P, Is, c2);
- }
-
- near_pnt[0] = near_pnt[1] = near_pnt[2] = 0.0;
- j = 0;
- for (i = 1; i <= GET(Is,s,0,c2); i++) { /** loop through all Is **/
- is = GET(Is,s,i,c2);
- near_indx[j] = is;
- lambda[j] = Di_P[s][is] / D_P[s]; /** eq. (17) **/
- VECADDS3(near_pnt, lambda[j], P[is], near_pnt); /** eq. (17) **/
- j++;
- }
-
- return (i-1);
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to compute the point in a polytope closest to the origin in
- * 3-space. The polytope size m is restricted to 1 < m <= 4.
- *
- * On Entry:
- * P - table of 3-element points containing polytope's vertices.
- * m - number of points in P.
- * near_pnt - an empty array of size 3.
- * near_indx - an empty array of size 4.
- * lambda - an empty array of size 4.
- *
- * On Exit:
- * near_pnt - the point in P closest to the origin.
- * near_indx - indices for a subset of P which is affinely independent.
- * See eq. (14).
- * lambda - the lambda as in eq. (14).
- *
- * Function Return :
- * the number of entries in near_indx and lambda.
- *
- ****************************************************************************/
-
- int sub_dist(P, m, near_pnt, near_indx, lambda)
- double P[][3], near_pnt[], lambda[];
- int near_indx[], m;
- {
- int size;
-
- /*
- *
- * Tables to index the Di_P cofactor table in comp_sub_dist. The s,i
- * entry indicates where to store the cofactors computed with Is_C.
- *
- */
-
- static int jo_2[2][2][2] = { {{0,0}, {2,1}},
- {{2,0}, {0,0}}};
-
- static int jo_3[6][3][2] = { {{0,0}, {3,1}, {4,2}},
- {{3,0}, {0,0}, {5,2}},
- {{4,0}, {5,1}, {0,0}},
- {{0,0}, {0,0}, {6,2}},
- {{0,0}, {6,1}, {0,0}},
- {{6,0}, {0,0}, {0,0}}};
-
- static int jo_4[14][4][2] = { { {0,0}, {4,1}, {5,2}, {6,3}},
- { {4,0}, {0,0}, {7,2}, {8,3}},
- { {5,0}, {7,1}, {0,0}, {9,3}},
- { {6,0}, {8,1}, {9,2}, {0,0}},
- { {0,0}, {0,0},{10,2},{11,3}},
- { {0,0},{10,1}, {0,0},{12,3}},
- { {0,0},{11,1},{12,2}, {0,0}},
- {{10,0}, {0,0}, {0,0},{13,3}},
- {{11,0}, {0,0},{13,2}, {0,0}},
- {{12,0},{13,1}, {0,0}, {0,0}},
- { {0,0}, {0,0}, {0,0},{14,3}},
- { {0,0}, {0,0},{14,2}, {0,0}},
- { {0,0},{14,1}, {0,0}, {0,0}},
- {{14,0}, {0,0}, {0,0}, {0,0}}};
-
-
- /*
- * These tables represent each Is. The first column of each row indicates
- * the size of the set.
- *
- */
- static int Is_2[3][3] = { {1,0,0}, {1,1,0}, {2,0,1}};
-
- static int Is_3[7][4] = { {1,0,0,0}, {1,1,0,0}, {1,2,0,0}, {2,0,1,0},
- {2,0,2,0}, {2,1,2,0}, {3,0,1,2}};
-
- static int Is_4[15][5] = { {1,0,0,0,0}, {1,1,0,0,0}, {1,2,0,0,0},
- {1,3,0,0,0}, {2,0,1,0,0}, {2,0,2,0,0},
- {2,0,3,0,0}, {2,1,2,0,0}, {2,1,3,0,0},
- {2,2,3,0,0}, {3,0,1,2,0}, {3,0,1,3,0},
- {3,0,2,3,0}, {3,1,2,3,0}, {4,0,1,2,3}};
-
- /*
- * These tables represent each Is complement. The first column of each row
- * indicates the size of the set.
- *
- */
- static int IsC_2[3][2] = { {1,1}, {1,0}, {0,0}};
-
- static int IsC_3[7][3] = { {2,1,2}, {2,0,2}, {2,0,1}, {1,2,0}, {1,1,0},
- {1,0,0}, {0,0,0}};
-
- static int IsC_4[15][4] = { {3,1,2,3}, {3,0,2,3}, {3,0,1,3}, {3,0,1,2},
- {2,2,3,0}, {2,1,3,0}, {2,1,2,0}, {2,0,3,0},
- {2,0,2,0}, {2,0,1,0}, {1,3,0,0}, {1,2,0,0},
- {1,1,0,0}, {1,0,0,0}, {0,0,0,0}};
-
-
- /** Call comp_sub_dist with appropriate tables according to size of P **/
-
- switch (m) {
- case 2:
- size = comp_sub_dist(P, m, jo_2, Is_2, IsC_2, near_pnt,
- near_indx, lambda);
- break;
- case 3:
- size = comp_sub_dist(P, m, jo_3, Is_3, IsC_3, near_pnt,
- near_indx, lambda);
- break;
- case 4:
- size = comp_sub_dist(P, m, jo_4, Is_4, IsC_4, near_pnt,
- near_indx, lambda);
- break;
- }
-
- return size;
- }
-
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to compute the minimum distance between two convex polytopes in
- * 3-space.
- *
- * On Entry:
- * P1 - table of 3-element points containing first polytope's vertices.
- * m1 - number of points in P1.
- * P2 - table of 3-element points containing second polytope's vertices.
- * m2 - number of points in P2.
- * VP - an empty array of size 3.
- * near_indx - a 4x2 matrix possibly containing indices of initialization
- * points. The first column are indices into P1, and the second
- * column are indices into P2.
- * lambda - an empty array of size 4.
- * m3 - a pointer to an int, which indicates how many initial points
- * to extract from near_indx. If 0, near_indx is ignored.
- *
- * On Exit:
- * Vp - vector difference of the two near points in P1 and P2.
- * The length of this vector is the minimum distance between P1
- * and P2.
- * near_indx - updated indices into P1 and P2 which indicate the affinely
- * independent point sets from each polytope which can be used
- * to compute along with lambda the near points in P1 and P2
- * as in eq. (12). These indices can be used to re-initialize
- * dist3d in the next iteration.
- * lambda - the lambda as in eqs. (11) & (12).
- * m3 - the updated number of indices for P1 and P2 in near_indx.
- *
- * Function Return : none.
- *
- ****************************************************************************/
-
- void dist3d(P1, m1, P2, m2, VP, near_indx, lambda, m3)
- double P1[][3], P2[][3], VP[], lambda[];
- int m1, m2, near_indx[][2], *m3;
- {
- Boolean pass;
- int set_size, I[4], i, j, i_tab[4], j_tab[4], P1_i, P2_i, k;
- double Hs(), Pk[4][3], Pk_subset[4][3], Vk[3], neg_Vk[3], Cp[3],
- Gp;
-
- if ((*m3) == 0) { /** if *m3 == 0 use single point initialization **/
- set_size = 1;
- VECSUB3(Pk[0], P1[0], P2[0]); /** first elementary polytope **/
- i_tab[0] = j_tab[0] = 0;
- }
- else { /** else use indices from near_indx **/
- for (k = 0; k < (*m3); k++) {
- i = i_tab[k] = near_indx[k][0];
- j = j_tab[k] = near_indx[k][1];
- VECSUB3(Pk[k], P1[i], P2[j]); /** first elementary polytope **/
- }
- set_size = *m3;
- }
-
- pass = FALSE;
- while (!pass) {
-
- /** compute Vk **/
-
- if (set_size == 1) {
- CPVECTOR3(Vk, Pk[0]);
- I[0] = 0;
- }
- else
- set_size = sub_dist(Pk, set_size, Vk, I, lambda);
-
- /** eq. (13) **/
-
- CPVECTOR3(neg_Vk, Vk); VECNEGATE3(neg_Vk);
- Gp = DOT3(Vk, Vk) + Hs(P1, m1, P2, m2, neg_Vk, Cp, &P1_i, &P2_i);
-
- /** keep track of indices for P1 and P2 **/
-
- for (i = 0; i < set_size; i++) {
- j = I[i];
- i_tab[i] = i_tab[j]; /** j is value from member of some Is **/
- j_tab[i] = j_tab[j]; /** j is value from member of some Is **/
- }
-
- if (EQZ(Gp)) /** Do we have a solution **/
- pass = TRUE;
- else {
- for (i = 0; i < set_size; i++) {
- j = I[i];
- CPVECTOR3(Pk_subset[i], Pk[j]); /** extract affine subset of Pk **/
- }
- for (i = 0; i < set_size; i++)
- CPVECTOR3(Pk[i], Pk_subset[i]); /** load into Pk+1 **/
-
- CPVECTOR3(Pk[i], Cp); /** Union of Pk+1 with Cp **/
- i_tab[i] = P1_i; j_tab[i] = P2_i;
- set_size++;
- }
- }
-
- CPVECTOR3(VP, Vk); /** load VP **/
- *m3 = set_size;
- for(i = 0; i < set_size; i++) {
- near_indx[i][0] = i_tab[i]; /** set indices of near pnt. in P1 **/
- near_indx[i][1] = j_tab[i]; /** set indices of near pnt. in P2 **/
- }
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to compute a proper separating plane between a pair of
- * polytopes. The plane will be a support plane for polytope 1.
- *
- * On Entry:
- * couple - couple structure for a pair of polytopes.
- *
- * On Exit:
- * couple - containing new proper separating plane, if one was
- * found.
- *
- * Function Return :
- * result of whether a separating plane exists, or not.
- *
- ****************************************************************************/
-
- Boolean get_new_plane(couple)
- Couple couple;
- {
- Polyhedron polyhedron1, polyhedron2;
- Boolean plane_exists;
- double pnts1[MAX_VERTS][3], pnts2[MAX_VERTS][3], dist,
- u[3], v[3], lambda[4], VP[3];
- int i, k, m1, m2;
-
- plane_exists = FALSE;
-
- polyhedron1 = couple->polyhdrn1; polyhedron2 = couple->polyhdrn2;
-
- /** Apply M1 to vertices of polytope 1 **/
-
- m1 = polyhedron1->m;
- for (i = 0; i < m1; i++) {
- CPVECTOR3(pnts1[i], polyhedron1->verts[i]);
- VECADD3(pnts1[i], pnts1[i], polyhedron1->trn);
- }
-
- /** Apply M2 to vertices of polytope 1 **/
-
- m2 = polyhedron2->m;
- for (i = 0; i < m2; i++) {
- CPVECTOR3(pnts2[i], polyhedron2->verts[i]);
- VECADD3(pnts2[i], pnts2[i], polyhedron2->trn);
- }
-
- /** solve eq. (1) for two polytopes **/
-
- dist3d(pnts1, m1, pnts2, m2, VP, couple->vert_indx, lambda, &couple->n);
-
- dist = sqrt(DOT3(VP,VP)); /** distance between polytopes **/
-
- if (!EQZ(dist)) { /** Does a separating plane exist **/
- plane_exists = TRUE;
- u[0] = u[1] = u[2] = v[0] = v[1] = v[2] = 0.0;
- for (i = 0; i < couple->n; i++) {
- k = couple->vert_indx[i][0];
- VECADDS3(u, lambda[i], pnts1[k], u); /** point in P1 **/
- k = couple->vert_indx[i][1];
- VECADDS3(v, lambda[i], pnts2[k], v); /** point in P2 **/
- }
-
- /** Store separating plane in P1's local coordinates **/
-
- VECADD3(u, u, polyhedron1->itrn);
- VECADD3(v, v, polyhedron1->itrn);
-
- /** Place separating plane in couple data structure **/
-
- CPVECTOR3(couple->pln_pnt1, u);
- CPVECTOR3(couple->pln_pnt2, v);
- }
- return plane_exists;
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to detect if two polyhedra are intersecting.
- *
- * On Entry:
- * couple - couple structure for a pair of polytopes.
- *
- * On Exit:
- *
- * Function Return :
- * result of whether polyhedra are intersecting or not.
- *
- ****************************************************************************/
-
- Boolean Collision(couple)
- Couple couple;
- {
- Polyhedron polyhedron1, polyhedron2;
- Boolean collide, loop;
- double u[3], v[3], norm[3], d;
- int i, m;
-
- polyhedron1 = couple->polyhdrn1; polyhedron2 = couple->polyhdrn2;
- collide = FALSE;
-
- if (couple->plane_exists) {
-
- /** Transform proper separating plane to P2 local coordinates. **/
- /** This avoids the computational cost of applying the **/
- /** transformation matrix to all the vertices of P2. **/
-
- CPVECTOR3(u, couple->pln_pnt1); CPVECTOR3(v, couple->pln_pnt2);
- VECADD3(u, u, polyhedron1->trn); VECADD3(v, v, polyhedron1->trn);
- VECADD3(u, u, polyhedron2->itrn); VECADD3(v, v, polyhedron2->itrn);
- VECSUB3(norm, v, u);
-
- m = polyhedron2->m; i = 0; loop = TRUE;
- while ((i < m) && (loop)) {
-
- /** Evaluate plane equation **/
-
- VECSUB3(v, polyhedron2->verts[i], u);
- d = DOT3(v, norm);
-
- if (d <= 0.0) { /** is P2 in opposite half-space **/
- loop = FALSE;
- if (!get_new_plane(couple)) {
- collide = TRUE; /** Collision **/
- couple->plane_exists = FALSE;
- }
- }
- i++;
- }
- }
- else
- if (get_new_plane(couple)) {
- couple->plane_exists = TRUE; /** No Collision **/
- }
- else
- collide = TRUE; /** Collision **/
-
- return collide;
- }
-
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to initialize a polyhedron.
- *
- * On Entry:
- * polyhedron - pointer to a polyhedron structure.
- * verts - verts to load.
- * m - number of verts.
- * tx - x translation.
- * ty - y translation.
- * tz - z translation.
- *
- * On Exit:
- * polyhedron - an initialized polyhedron.
- *
- * Function Return : none.
- *
- ****************************************************************************/
-
- void init_polyhedron(polyhedron, verts, m, tx, ty, tz)
- Polyhedron polyhedron;
- double *verts, tx, ty, tz;
- int m;
- {
- int i;
- double *p;
-
- polyhedron->trn[0] = tx; polyhedron->trn[1] = ty;
- polyhedron->trn[2] = tz;
-
- polyhedron->itrn[0] = -tx; polyhedron->itrn[1] = -ty;
- polyhedron->itrn[2] = -tz;
-
- polyhedron->m = m;
-
- p = verts;
- for (i = 0; i < m; i++) {
- CPVECTOR3(polyhedron->verts[i], p);
- p += 3;
- }
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * Function to move a polyhedron.
- *
- * On Entry:
- * polyhedron - pointer to a polyhedron.
- * tx - x translation.
- * ty - y translation.
- * tz - z translation.
- *
- * On Exit:
- * polyhedron - an updated polyhedron.
- *
- * Function Return : none.
- *
- ****************************************************************************/
-
- void move_polyhedron(polyhedron, tx, ty, tz)
- Polyhedron polyhedron;
- double tx, ty, tz;
- {
- polyhedron->trn[0] += tx; polyhedron->trn[1] += ty;
- polyhedron->trn[2] += tz;
-
- polyhedron->itrn[0] -= tx; polyhedron->itrn[1] -= ty;
- polyhedron->itrn[2] -= tz;
- }
-
- /*** RJR 05/26/93 ***********************************************************
- *
- * This is the Main Program for the Collision Detection example. This test
- * program creates the vertices of three polyhedra: a sphere, a box, and a
- * cylinder. The three polyhedra oscillate back and forth along the x-axis.
- * A collision test is done after each movement on each pair of polyhedra.
- * This test program was run on an SGI Onyx/4 and an SGI 4D/80. A total of
- * 30,000 collision detection tests were performed. There were 3,160
- * collisions detected. The dist3d function was called in 14% of the
- * collision tests. The average number of iterations in dist3d was 1.7.
- * The above functions are designed to compute accurate solutions when
- * the polyhedra are simple and convex. The functions will work on
- * concave polyhedra, but the solutions are computed using the convex hulls
- * of the concave polyhedra. In this case when the algorithm returns a
- * disjoint result it is exact, but when it returns an intersection result
- * it is approximate.
- *
- ****************************************************************************/
- main()
- {
- Polyhedron Polyhedron1, Polyhedron2, Polyhedron3;
- Couple Couple1, Couple2, Couple3;
- double xstp1, xstp2, xstp3;
- int i, steps;
- long hits = 0;
-
- /*** Initialize the 3 test polyhedra ***/
-
- mak_box(box);
- mak_cyl(cyl);
- mak_sph(sphere);
-
- Polyhedron1 = (Polyhedron)malloc(sizeof(struct polyhedron));
- init_polyhedron(Polyhedron1, sphere, 342, 0.0, 0.0, 0.0);
-
- Polyhedron2 = (Polyhedron)malloc(sizeof(struct polyhedron));
- init_polyhedron(Polyhedron2, box, 8, 50.0, 0.0, 0.0);
-
- Polyhedron3 = (Polyhedron)malloc(sizeof(struct polyhedron));
- init_polyhedron(Polyhedron3, cyl, 36, -50.0, 0.0, 0.0);
-
- Couple1 = (Couple)malloc(sizeof(struct couple));
- Couple1->polyhdrn1 = Polyhedron1; Couple1->polyhdrn2 = Polyhedron2;
- Couple1->n = 0;
- Couple1->plane_exists = FALSE;
-
- Couple2 = (Couple)malloc(sizeof(struct couple));
- Couple2->polyhdrn1 = Polyhedron1; Couple2->polyhdrn2 = Polyhedron3;
- Couple2->n = 0;
- Couple2->plane_exists = FALSE;
-
- Couple3 = (Couple)malloc(sizeof(struct couple));
- Couple3->polyhdrn1 = Polyhedron3; Couple3->polyhdrn2 = Polyhedron2;
- Couple3->n = 0;
- Couple3->plane_exists = FALSE;
-
- /** Perform Collision Tests **/
-
- xstp1 = 1.0; xstp2 = 5.0; xstp3 = 10.0; steps = 10000;
-
- for (i = 0; i < steps; i++) {
- move_polyhedron(Polyhedron1, xstp1, 0.0, 0.0);
- move_polyhedron(Polyhedron2, xstp2, 0.0, 0.0);
- move_polyhedron(Polyhedron3, xstp3, 0.0, 0.0);
-
- if (Collision(Couple1))
- hits++;
- if (Collision(Couple2))
- hits++;
- if (Collision(Couple3))
- hits++;
-
- if (ABS(Polyhedron1->trn[0]) > 100.0)
- xstp1 = -xstp1;
- if (ABS(Polyhedron2->trn[0]) > 100.0)
- xstp2 = -xstp2;
- if (ABS(Polyhedron3->trn[0]) > 100.0)
- xstp3 = -xstp3;
- }
- printf("number of tests = %d\n",(steps * 3));
- printf("number of hits = %ld\n", hits);
- }
-